#pragma code_seg("CSAMBA")
#pragma data_seg("DSAMBA")
#pragma bss_seg("BSAMBA")
#pragma const_seg("KSAMBA")
#pragma comment(linker, "/merge:DSAMBA=SAMBA")
#pragma comment(linker, "/merge:CSAMBA=SAMBA")
#pragma comment(linker, "/merge:BSAMBA=SAMBA")
#pragma comment(linker, "/merge:KSAMBA=SAMBA")
/*

    This file is part of the smb++ library

    Copyright (C) 1999  Nicolas Brodu

    nicolas.brodu@free.fr



    This program is free software; you can redistribute it and/or modify

    it under the terms of the GNU General Public License as published by

    the Free Software Foundation; either version 2 of the License, or

    (at your option) any later version.



    This program is distributed in the hope that it will be useful,

    but WITHOUT ANY WARRANTY; without even the implied warranty of

    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

    GNU General Public License for more details.



    You should have received a copy of the GNU General Public License

    along with this program, see the file COPYING; if not, write

    to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,

    MA 02139, USA.

*/

#include "defines.h"

//#ifndef USE_SAMBA



#ifdef _WIN32

#ifdef _XBOX

#include <xtl.h>

#undef errno

#define getpid() 1

#else

#include <windows.h>

#define getpid() (unsigned short)GetCurrentProcessId()

#endif

#define getuid() 500

#define getgid() 500

#else

#include <unistd.h> // for getpid(), getuid(), getgid()

#endif

#include <fcntl.h>	// need open() flags

#include <string.h>

#include <time.h>	// needed for mktime() and tm, time_t structs

#include "SMBPacket.h"

#include "SMBCodes.h"



#ifdef DEBUG

#include <iostream.h>

#include <stdio.h>

#endif



SMBPacket::SMBPacket(uint8 dial)

{

	dialect=dial;



	smb_pid=getpid();

	smb_mid=0;  // We'll see if we need multiplexed connections later

	smb_uid=0;	// We are not registered yet

	smb_tid=0;	// We are not registered yet

	smb_err=SUCCESS;

	smb_rcls=SUCCESS;

	smb_com=SMBnegprot; // Should be overrided later on

	

	smb_wct=0;

	smb_bcc=0;

	smb_buf=0;

	smb_vwv=0;

	

	modified=1;

}



SMBPacket::~SMBPacket()

{

	if (smb_buf) delete smb_buf;

	if (smb_vwv) delete smb_vwv;

}





void SMBPacket::update()

{

	if (!modified) return;

	if (data) delete data;

	// The 3 at the end of next line stands for size of smb_wct and smb_bcc

	length=32+((uint16)smb_wct)*2+smb_bcc+3;

	data = new uint8[length];

	data[0]=0xFF; data[1]='S'; data[2]='M'; data[3]='B';

	data[4]=smb_com;

	data[5]=smb_rcls;

	data[6]=0;	// reserved	- flags in later protocols

	data[7]=(uint8)(smb_err&0xFF); // little endian

	data[8]=(uint8)(smb_err>>8); // little endian

	data[9]=0; // reserved

	data[10]=1; // reserved

	data[11]=0; // reserved

	for (int i=12; i<24; i++) data[i]=0; // reserved

	data[24]=(uint8)(smb_tid&0xFF); // little endian

	data[25]=(uint8)(smb_tid>>8); // little endian

	data[26]=(uint8)(smb_pid&0xFF); // little endian

	data[27]=(uint8)(smb_pid>>8); // little endian

	data[28]=(uint8)(smb_uid&0xFF); // little endian

	data[29]=(uint8)(smb_uid>>8); // little endian

	data[30]=(uint8)(smb_mid&0xFF); // little endian

	data[31]=(uint8)(smb_mid>>8); // little endian

	data[32]=smb_wct;

	if (smb_wct) memcpy(data+33,(uint8*)smb_vwv,((uint16)smb_wct)*2);

	data[33+((uint16)smb_wct)*2]=(uint8)(smb_bcc&0xFF);

	data[34+((uint16)smb_wct)*2]=(uint8)(smb_bcc>>8);

	if (smb_bcc) memcpy(data+35+((uint16)smb_wct)*2,smb_buf,smb_bcc);

	modified=0;

}



// converts parents data field into our structure

int SMBPacket::parse(SessionPacket *p)

{

	if (SessionPacket::parse(p)==-1) return -1;

	

	// First check for a consistent length

	if (length<35) 	// min size

	{

		errno=ERRCMD;	// not in smb format

		return -1;

	}

	smb_wct=data[32];

	if (smb_wct)

	{

		if (length<35+((uint16)smb_wct)*2)

		{

			errno=ERRCMD;	// not in smb format

			return -1;

		}

		if (smb_vwv) delete smb_vwv;

		smb_vwv=new uint16[((uint16)smb_wct)*2];

#ifdef WORDS_BIGENDIAN

		for (int i=0; i<(uint16)smb_wct; i++)

			smb_vwv[i]=(uint16)(*(data+33+i*2)) | (uint16)((*(data+34+i*2))<<8);

#else

		memcpy(smb_vwv,data+33,((uint16)smb_wct)*2);

#endif

	}	

	// little endian

	smb_bcc=(uint16)(data[33+((uint16)smb_wct)*2]) | ((uint16)(data[34+((uint16)smb_wct)*2])<<8);

	if (smb_bcc)

	{

		if (length<35+((uint16)smb_wct)*2+smb_bcc)

		{

			errno=ERRCMD;	// not in smb format

			return -1;

		}

		if (smb_buf) delete smb_buf;

		smb_buf=new uint8[smb_bcc];

		memcpy(smb_buf,data+35+((uint16)smb_wct)*2,smb_bcc);

	}

#if DEBUG >= 5

	cout<<"Parse : word count : "<<(uint16)smb_wct<<" byte count : "<<(uint16)smb_bcc<<"\n";;

#endif

	

	// now update remaining fields

	smb_com=data[4];

	smb_rcls=data[5];

	smb_err=(uint16)(data[7]) | ((uint16)(data[8])<<8);

	smb_tid=(uint16)(data[24]) | ((uint16)(data[25])<<8);

	smb_pid=(uint16)(data[26]) | ((uint16)(data[27])<<8);

	smb_uid=(uint16)(data[28]) | ((uint16)(data[29])<<8);

	smb_mid=(uint16)(data[30]) | ((uint16)(data[31])<<8);



	modified=0;	

	return 1;

}





uint8 SMBPacket::getSMBType()

{

	if (modified) update();

	return smb_com;

}



uint16 SMBPacket::getError()

{

	if (modified) update();

	return smb_err;

}





// Parent virtuals

uint16 SMBPacket::getDataLength()

{

	if (modified) update();

	return length;

}



uint8 *SMBPacket::getData()

{

	if (modified) update();

	return data;

}









/**********************

Now the command Packets

***********************/



/* open file */

SMBopenPacket::SMBopenPacket(uint16 TID, const char *filename, int flags, uint8 dial) : SMBPacket(dial)

{

	smb_com=SMBopen;

	smb_tid=TID;

	

	smb_wct=2;

	smb_vwv=new uint16[2];

	uint16 access=0;

	if (flags & O_RDONLY) access=0;

	if (flags & O_WRONLY) access=0x5001;

	if (flags & O_RDWR) access=0x5002;

	smb_vwv[0]=access; // will be converted in little endian later

	smb_vwv[1]=0x27;   // DOS attributes for all files types except 'directory' & 'volume'

	

	if (filename)

	{

		smb_bcc=2+strlen(filename);

		smb_buf=new uint8[smb_bcc];

		smb_buf[0]=4;	// data is ASCIIZ

		strcpy((char*)(smb_buf+1), filename);

		smb_buf[smb_bcc-1]=0;

	}

	else

	{

		smb_bcc=2;

		smb_buf=new uint8[smb_bcc];

		smb_buf[0]=4;	// data is ASCIIZ

		smb_buf[1]=0;	// empty string

	}

	modified=1;

}



uint16 SMBopenPacket::getFID()

{

	if (smb_wct>=7)

	{

		errno=SUCCESS;

		return smb_vwv[0];

	}

	else

	{

		errno=ERRbadformat;

		return 0xFFFF;

	}

}





/* create file */

SMBcreatePacket::SMBcreatePacket(uint16 TID, const char *filename, uint8 dial) : SMBPacket(dial)

{

	smb_com=SMBcreate;

	smb_tid=TID;

	

	smb_wct=3;

	smb_vwv=new uint16[smb_wct];

	smb_vwv[0]=0x20;   // DOS attribute for "archive"

	smb_vwv[1]=0;   // creation time, optional

	smb_vwv[2]=0;   // creation date, optional

	

	if (filename)

	{

		smb_bcc=2+strlen(filename);

		smb_buf=new uint8[smb_bcc];

		smb_buf[0]=4;	// data is ASCIIZ

		strcpy((char*)(smb_buf+1), filename);

		smb_buf[smb_bcc-1]=0;

	}

	else

	{

		smb_bcc=2;

		smb_buf=new uint8[smb_bcc];

		smb_buf[0]=4;	// data is ASCIIZ

		smb_buf[1]=0;	// empty string

	}

	modified=1;

}



uint16 SMBcreatePacket::getFID()

{

	if (smb_wct>=1)

	{

		errno=SUCCESS;

		return smb_vwv[0];

	}

	else

	{

		errno=ERRbadformat;

		return 0xFFFF;

	}

}





SMBgetatrPacket::SMBgetatrPacket(uint16 tid, const char *filename, uint8 dial) : SMBPacket(dial)

{

	smb_com=SMBgetatr;

	smb_tid=tid;

	

	smb_wct=0;

	

	if (filename)

	{

		smb_bcc=2+strlen(filename);

		smb_buf=new uint8[smb_bcc];

		smb_buf[0]=4;	// data is ASCIIZ

		strcpy((char*)(smb_buf+1), filename);

		smb_buf[smb_bcc-1]=0;

	}

	else

	{

		smb_bcc=2;

		smb_buf=new uint8[smb_bcc];

		smb_buf[0]=4;	// data is ASCIIZ

		smb_buf[1]=0;	// empty string

	}

	modified=1;

}



SMBwritePacket::SMBwritePacket(uint16 tid, uint16 fid, uint32 offset, uint8* buf, uint16 length, uint8 dial) : SMBPacket(dial)

{

	smb_com=SMBwrite;

	smb_tid=tid;

	smb_wct=5;

	smb_vwv=new uint16[smb_wct];

	smb_vwv[0]=fid;

	smb_vwv[1]=length;

	smb_vwv[2]=(uint16)(offset&0xFFFF);

	smb_vwv[3]=(uint16)(offset>>16);

	smb_vwv[4]=0;

	smb_bcc=length+3; // plus data description

	smb_buf=new uint8[smb_bcc];

	smb_buf[0]=1;	// data is a block

	smb_buf[1]=(uint8)(length&0xFF);    // length in little endian

	smb_buf[2]=(uint8)(length>>8)&0xFF;

	memcpy(smb_buf+3,buf,length);

	modified=1;

}



int32 SMBwritePacket::getWrittenCount()

{

	if (smb_wct>=1)

	{

		errno=SUCCESS;

		return smb_vwv[0];

	}

	else

	{

		errno=ERRbadformat;

		return -1;

	}

}



SMBreadPacket::SMBreadPacket(uint16 tid, uint16 fid, uint32 offset, uint16 count, uint8 dial) : SMBPacket(dial)

{

	smb_com=SMBread;

	smb_tid=tid;

	smb_wct=5;

	smb_vwv=new uint16[smb_wct];

	smb_vwv[0]=fid;

	smb_vwv[1]=count;

	smb_vwv[2]=(uint16)(offset&0xFFFF);

	smb_vwv[3]=(uint16)(offset>>16);

	smb_vwv[4]=0;

	modified=1;

}



uint16 SMBreadPacket::getReadCount()

{

	if (smb_bcc>=3)

	{

		errno=SUCCESS;

		// should we return the count in smb_vwv[0] or

		// the actual data length ?

		// I'd trust the server to fill in data length, so...

//		cout<<"count : "<<(uint16)smb_vwv[0]<<"\n";

		uint16 len=(((uint16)(smb_buf[1])&0xFF)|((uint16)(smb_buf[2])<<8));

//		cout<<"len : "<<(uint16)len<<"\n";

		return len;

	}

	else

	{

		errno=ERRbadformat;

		return 0;

	}

}



uint8 *SMBreadPacket::getReadData()

{

	if (smb_bcc>=3)

	{

		uint16 n=getReadCount();

		if (smb_bcc!=3+n)

		{

			errno=ERRbadformat;

			return 0;

		}

		uint8 *ret=new uint8[n];

		memcpy(ret, smb_buf+3, n);

		errno=SUCCESS;

		return ret;

	}

	else

	{

		errno=ERRbadformat;

		return 0;

	}

}





SMBreadBrawPacket::SMBreadBrawPacket(uint16 tid, uint16 fid, uint32 offset, uint16 count, uint8 dial) : SMBPacket(dial)

{

	smb_com=SMBreadBraw;

	smb_tid=tid;

	smb_wct=8;

	smb_vwv=new uint16[smb_wct];

	smb_vwv[0]=fid;

	smb_vwv[1]=(uint16)(offset&0xFFFF);

	smb_vwv[2]=(uint16)(offset>>16);

	smb_vwv[3]=count;

	smb_vwv[4]=0;

	smb_vwv[5]=0;

	smb_vwv[6]=0;

	smb_vwv[7]=0;

	modified=1;

}



SMBwriteBrawPacket::SMBwriteBrawPacket(uint16 tid, uint16 fid, uint32 offset, uint16 totalLength, uint8 dial) : SMBPacket(dial)

{

	smb_com=SMBwriteBraw;

	smb_tid=tid;

	smb_wct=12;

	smb_vwv=new uint16[smb_wct];

	smb_vwv[0]=fid;

	smb_vwv[1]=totalLength; // total data that will be sent

#if DEBUG >= 6

	cout<<"SMBwriteBrawPacket : totalLength="<<totalLength<<"\n";

#endif

	smb_vwv[2]=0; // reserved

	smb_vwv[3]=(uint16)(offset&0xFFFF);

	smb_vwv[4]=(uint16)(offset>>16);

	smb_vwv[5]=0xFFFF; // timeout in little endian

	smb_vwv[6]=0x0FFF; // timeout - end

	smb_vwv[7]=1; // write mode = send final confirmation (never too cautious with smb...)

	smb_vwv[8]=0; // reserved

	smb_vwv[9]=0; // reserved

	smb_vwv[10]=0; // 0 bytes send in this request, we won't "optimize" for now...

	smb_vwv[11]=0; // offset to data from header start : not important !

	modified=1;

}





struct stat *SMBgetatrPacket::getStat()

{

	if (smb_wct>=10)

	{

		errno=SUCCESS;

		struct stat *s=(struct stat*)(new uint8[sizeof(struct stat)]);

		s->st_mode=0644; //default

		// archive attribute mapped to 0644

		if (smb_vwv[0]&0x20) s->st_mode|=0644;

		// read-only attribute removes write permission

		if (smb_vwv[0]&0x01) s->st_mode&=077666;

		// directory attribute mapped to 040755

		if (smb_vwv[0]&0x10) s->st_mode|=040755;

		// Anyone has any idea about what volume, hidden and

		// system should be mapped to ???

		struct tm footm;

		footm.tm_sec=(smb_vwv[1]&0x1F)<<1; // 2 sec increments

		footm.tm_min=(smb_vwv[1]&0x7E0)>>5; // minutes

		footm.tm_hour=(smb_vwv[1]&0xF800)>>11; // hour

		footm.tm_mday=smb_vwv[2]&0x1F; // day of month

		footm.tm_mon=((smb_vwv[1]&0x1E0)>>5)-1; // month 1..12 => 0..11

		// And make us ready for year 2100 bug...

		footm.tm_year=((smb_vwv[1]&0xFE00)>>9)+80; // weird 0..119 interval from 1980

		footm.tm_isdst=-1; // daylight info not available

		s->st_atime=mktime(&footm); // computes wday and yday and converts to time_t type

		s->st_mtime=s->st_atime; // same date/time for last access

		s->st_ctime=s->st_atime; // modification and change

		s->st_uid=getuid(); // so we're sure user exist, access rights have been set

		s->st_gid=getgid(); // It would be better if owner was "nobody"

		s->st_size=(uint32)(smb_vwv[3]) | ((uint32)(smb_vwv[4]) << 16);
#ifdef _WIN32_
		s->st_blksize=1024;            // why not ?
		s->st_blocks=s->st_size >> 10;
#endif
		s->st_rdev=0100000; // regular file

		return s;

	}

	else

	{

		errno=ERRbadformat;

		return 0;

	}

}





SMBclosePacket::SMBclosePacket(uint16 fid)

{

	smb_com=SMBclose;

	smb_wct=3;

	smb_vwv=new uint16[smb_wct];

	smb_vwv[0]=fid;

	smb_vwv[1]=0; // time and date will

	smb_vwv[2]=0; // be set by server

	modified=1;

}



SMBunlinkPacket::SMBunlinkPacket(uint16 TID, const char *filename, uint8 dial) : SMBPacket(dial)

{

	smb_com=SMBunlink;

	smb_tid=TID;

	

	smb_wct=1;

	smb_vwv=new uint16[smb_wct];

	smb_vwv[0]=0x26; // DOS attribute for "archive", "hidden", "system"

	

	if (filename)

	{

		smb_bcc=2+strlen(filename);

		smb_buf=new uint8[smb_bcc];

		smb_buf[0]=4;	// data is ASCIIZ

		strcpy((char*)(smb_buf+1), filename);

		smb_buf[smb_bcc-1]=0;

	}

	else

	{

		smb_bcc=2;

		smb_buf=new uint8[smb_bcc];

		smb_buf[0]=4;	// data is ASCIIZ

		smb_buf[1]=0;	// empty string

	}

	modified=1;

}





SMBmkdirPacket::SMBmkdirPacket(uint16 TID, const char *pathname, uint8 dial) : SMBPacket(dial)

{

	smb_com=SMBmkdir;

	smb_tid=TID;

	

	smb_wct=0;

	

	if (pathname)

	{

		smb_bcc=2+strlen(pathname);

		smb_buf=new uint8[smb_bcc];

		smb_buf[0]=4;	// data is ASCIIZ

		strcpy((char*)(smb_buf+1), pathname);

		smb_buf[smb_bcc-1]=0;

	}

	else

	{

		smb_bcc=2;

		smb_buf=new uint8[smb_bcc];

		smb_buf[0]=4;	// data is ASCIIZ

		smb_buf[1]=0;	// empty string

	}

	modified=1;

}





SMBrmdirPacket::SMBrmdirPacket(uint16 TID, const char *pathname, uint8 dial) : SMBmkdirPacket(TID, pathname, dial)

{

	smb_com=SMBrmdir;

	modified=1;

}



SMBmvPacket::SMBmvPacket(uint16 TID, const char *srcfile, const char *dstfile, uint8 dial)  : SMBPacket(dial)

{

	smb_com=SMBmv;

	smb_tid=TID;

	

	if ((!srcfile) || (!dstfile)) return; // no need to go further on

	

	smb_wct=1;

	smb_vwv=new uint16[smb_wct];

	smb_vwv[0]=6; // search attributes : include "system" and "hidden" files

	

	smb_bcc=4+strlen(srcfile)+strlen(dstfile);

	smb_buf=new uint8[smb_bcc];

	smb_buf[0]=4;	// data is ASCIIZ

	strcpy((char*)(smb_buf+1), srcfile);

	smb_buf[2+strlen(srcfile)]=4;	// data is ASCIIZ

	strcpy((char*)(smb_buf+3+strlen(srcfile)), dstfile);

	smb_buf[smb_bcc-1]=0;

	modified=1;

}



const int SMBnegprotPacket::NbDialect=6;

const char *SMBnegprotPacket::dialect[] =

{

"PC NETWORK PROGRAM 1.0",

"PCLAN1.0",

"MICROSOFT NETWORKS 1.03",

"MICROSOFT NETWORKS 3.0",

"DOS LANMAN1.0",

"LANMAN1.0"

/*"LM1.2X002",

"DOS LM1.2X002",

"DOS LANMAN2.1",

"LANMAN2.1",

"Samba",

"NT LM 0.12",

"NT LANMAN 1.0"*/

};

SMBnegprotPacket::SMBnegprotPacket(uint8 dial) : SMBPacket(dial)

{

	smb_com=SMBnegprot;

	smb_bcc=0;

	for (int i=0; i<NbDialect; i++) smb_bcc+=strlen(dialect[i])+2;

	smb_buf = new uint8[smb_bcc];

	char *tmp=(char*)smb_buf;

#ifdef _WIN32

	for (i=0; i<NbDialect; i++)

#else

	for (int i=0; i<NbDialect; i++)

#endif

	{

		*tmp=2;	// Data type = dialect

		strcpy(tmp+1, dialect[i]);

		tmp+=strlen(dialect[i])+2;

	}

	modified=1;

}



int16 SMBnegprotPacket::getAcceptedDialect()

{

	if (smb_wct>=1)

	{

#if DEBUG >= 4

	cout<<"Negotiation Protocol :\n"<<"wct : "<<(int)smb_wct<<"\n";

	if (smb_wct>=13)

	{

		cout<<"index : "<<smb_vwv[0]<<"\n";

		cout<<"Security  : "<<smb_vwv[1]<<"\n";

		cout<<"MaxBufSize : "<<smb_vwv[2]<<"\n";

		cout<<"MaxMux : "<<smb_vwv[3]<<"\n";

		cout<<"MaxConnect : "<<smb_vwv[4]<<"\n";

		cout<<"RawMode : "<<smb_vwv[5]<<"\n";

		cout<<"SessionKey : "<<(uint32)((uint32)(smb_vwv[6]) | (uint32)(smb_vwv[7])<<16) <<"\n";

		cout<<"Time : "<<smb_vwv[8]<<smb_vwv[9]<<"\n";

		cout<<"Date : "<<smb_vwv[10]<<smb_vwv[11]<<"\n";

		cout<<"TimeZone : "<<smb_vwv[12]<<"\n";

	}

	cout<<"smb_buf length : "<<(int)smb_bcc<<"\n";

	cout<<"smb_buf : ";

	for (int i=0; i<smb_bcc; i++) printf("%X ",smb_buf[i]); cout<<"\n";

#endif

		errno=SUCCESS;

		return smb_vwv[0];

	}

	else

	{

		errno=ERRbadformat;

		return -1;

	}

}



int16 SMBnegprotPacket::getSecurityMode()

{

	if (smb_wct>=2)

	{

		errno=SUCCESS;

		return smb_vwv[1];

	}

	else

	{

		errno=ERRbadformat;

		return -1;

	}

}



int16 SMBnegprotPacket::getMaxMessageSize()

{

	if (smb_wct>=3)

	{

		errno=SUCCESS;

		return smb_vwv[2];

	}

	else

	{

		errno=ERRbadformat;

		return -1;

	}

}



// return the key if any, null otherwise

// the length of the key will be return throught

// the int in argument

uint8* SMBnegprotPacket::getCryptKey(int &length)

{

	uint8* ret=0;

	length=0;

	if (smb_bcc>=8)

	{

		ret=new uint8[8];

		memcpy((char*)ret,(char*)smb_buf,8);

		length=8;

	}

	return ret;

}



uint32 SMBnegprotPacket::getSessionKey()

{

	if (smb_wct>=7)

		return (uint32)((uint32)(smb_vwv[6]) | (uint32)(smb_vwv[7])<<16);

	else

	{

		errno=ERRbadformat;

		return 0xFFFFFFFF;

	}

}



uint8 SMBnegprotPacket::isReadRawPossible()

{

	if (smb_wct>=6)

		return (uint8)(smb_vwv[5] & 1);

	else

	{

		errno=ERRbadformat;

		return 0; // 0 and not 0xFF, so that the program has a chance to work

	}             // since it will not use readRaw (boolean).

}





SMBtconPacket::SMBtconPacket(const char* chemin, const uint8* pass, uint32 length, const char* dev, uint8 dial) : SMBPacket(dial)

{

	smb_com=SMBtcon;

	path=0; password=0; device=0;

	passLen=0;

	setPath(chemin);

	setPassword(pass, length);

	setDevice(dev);

}
SMBtconPacket::~SMBtconPacket()
{
  if( password ) 
    delete password;
  if( path )
    delete path;
}

void SMBtconPacket::setPath(const char *chemin)

{

	if (path) delete path;

	if (chemin)

	{

		path = new char[strlen(chemin)+1];

		strcpy(path,chemin);

	}

	else

	{

		path = new char[1];

		path[0]=0;

	}

	modified=1;

}



void SMBtconPacket::setPassword(const uint8 *pass, uint32 length)

{

	if (password) delete password;

	if (pass)

	{

		passLen=length;

		password = new uint8[passLen];

		memcpy(password,pass,passLen);

	}

	else

	{

		passLen=1;

		password = new uint8[1];

		password[0]=0;

	}

	modified=1;

}



void SMBtconPacket::setDevice(const char *dev)

{

	if (device) delete device;

	if (dev)

	{

		device = new char[strlen(dev)+1];

		strcpy(device,dev);

	}

	else

	{

		device = new char[1];

		device[0]=0;

	}

	modified=1;

}



void SMBtconPacket::update()

{

	if (!modified) return;

	if (smb_buf) delete (smb_buf);

	if (smb_vwv) delete (smb_vwv);

	if (!path) setPath("");

	if (!password) setPassword(0,0);

	if (!device) setDevice("");

	smb_wct=0;

	int l1=strlen(path)+1;

	int l2=passLen;

	int l3=strlen(device)+1;

	smb_bcc=l1+l2+l3+3;	// +3 for the 3 data id

	smb_buf=new uint8[smb_bcc];

	smb_buf[0]=4;	// data id for ASCIIZ

	smb_buf[l1+1]=4;	// data id for ASCIIZ

	smb_buf[l1+l2+2]=4;	// data id for ASCIIZ

	memcpy(smb_buf+1,path,l1);

	memcpy(smb_buf+l1+2,password,l2);

	memcpy(smb_buf+l1+l2+3,device,l3);

	SMBPacket::update();

}



uint16 SMBtconPacket::getMaxMessageSize()

{

	if (smb_wct) return smb_vwv[0];

	else

	{

		errno=ERRbadformat;

		return 0;	// can't put -1, 0xFFFF is a valid answer

	}

}



uint16 SMBtconPacket::getTID()

{

	if (smb_wct>=2) return smb_vwv[1];

	else

	{

		errno=ERRbadformat;

		return (uint16)-1;

	}

}



SMBtconXPacket::SMBtconXPacket(const char* chemin, const uint8* pass, uint32 length, const char* dev, uint8 dial) :

		SMBtconPacket(chemin, pass, length, dev, dial)

{

	smb_com=SMBtconX;

#if DEBUG>=6

	printf("SMBtconXPacket : constructor :\n");

	cout<<"passLen : "<<passLen<<"\npass :\n";

	for (uint16 i=0; i<passLen; i++) printf("%X ",password[i]);

	printf("\n");

#endif

}



void SMBtconXPacket::update()

{

	if (!modified) return;

	if (smb_buf) delete (smb_buf);

	if (smb_vwv) delete (smb_vwv);

	if (!path) setPath("");

	if (!password) setPassword(0,0);

	if (!device) setDevice("");

	smb_wct=4;

	smb_vwv=new uint16[4];

	smb_vwv[0]=0x00FF;	// AndX command, will be stored in litle endian

	smb_vwv[1]=0;	// offset to next command wordcount

	smb_vwv[2]=0;	// flags : 0

	smb_vwv[3]=(uint16)passLen;	// that's why TreeconX and not Treecon

	int l1=passLen;

	int l2=strlen(path)+1;

	int l3=strlen(device)+1;

	smb_bcc=l1+l2+l3;	// only lengths, no data id here !!!

	smb_buf=new uint8[smb_bcc];

	memcpy(smb_buf,password,passLen);

#if DEBUG>=6

	printf("SMBtconXPacket : Pass sent to server :\n");

	for (uint16 i=0; i<passLen; i++) printf("%X ",password[i]);

	printf("\n");

#endif

	memcpy(smb_buf+passLen,path,l2);

	memcpy(smb_buf+passLen+l2,device,l3);

	SMBPacket::update();

}



uint16 SMBtconXPacket::getMaxMessageSize()

{

	errno=ERRbadformat; // only for tcon... not present in tconX !

	return 0;	// can't put -1, 0xFFFF is a valid answer

}



uint16 SMBtconXPacket::getTID()

{

	return smb_tid; // no field in doc, ???

}



SMBtdisPacket::SMBtdisPacket(uint16 tid, uint8 dial) : SMBPacket(dial)

{

	smb_com=SMBtdis;

	smb_tid=tid;

	modified=1;

}





SMBsesssetupPacket::SMBsesssetupPacket(uint32 sessionKey, const char* account, uint8 *pass, uint16 passLen, uint16 UID, uint8 dial) : SMBPacket(dial)

{

	smb_com=SMBsesssetup;

	smb_uid=UID;

	

	smb_wct=10;

	smb_vwv=new uint16[10];

	smb_vwv[0]=0x00FF;	// AndX command, will be stored in litle endian

	smb_vwv[1]=0;	// offset to next command wordcount

	smb_vwv[2]=0xFFFF;	// max buf size, we don't care

	smb_vwv[3]=0;	// Max multiplexed pending request

	smb_vwv[4]=0;	// "Virtual Circuit"=tcp/ip connection number

	smb_vwv[5]=sessionKey&0xFFFF;	// Session key if V.C. above<>0

	smb_vwv[6]=(uint32)sessionKey>>16;

	smb_vwv[7]=passLen;	// Password length

	smb_vwv[8]=0; smb_vwv[9]=0;	// CIFS : reserved, Lanman1 : encrypt



/*	char *emptyString="";

	if (!account) account=emptyString;

	uint16 accLen=strlen(account)+1; //(account) ? strlen(account)+1 : 0;

	if (passLen==0) {

		pass=(uint8*)emptyString;

		passLen=1;

	}*/

	uint16 accLen=(account)?strlen(account)+1:0;

	if (!pass) passLen=0;

	smb_bcc=accLen+passLen;

	if (smb_bcc) smb_buf=new uint8[smb_bcc];

	if (passLen) memcpy(smb_buf,pass,passLen);

	if (accLen) strcpy((char*)smb_buf+passLen,account);



	modified=1;

#if DEBUG >=6

	print();

#endif

}





SMBtransPacket::SMBtransPacket(uint16 tid, const char* transactName,

		uint16 *setup, uint16 setupLength, // # of uint16

		uint16 totalParameterCount,

		uint16 totalDataCount,

		uint8* param, uint16 paramLength,

		uint8* data, uint16 dataLength, uint8 dial)

{

	smb_tid=tid;

	smb_com=(transactName)?SMBtrans:SMBtrans2;

	smb_wct=14+setupLength;

	smb_vwv=new uint16[smb_wct];

	smb_vwv[0]=totalParameterCount;

	smb_vwv[1]=totalDataCount;

	smb_vwv[2]=0x400; // max paramCount to return : limit it to

	smb_vwv[3]=0x400; // max dataCount : 1kB bytes because windows

	smb_vwv[4]=0X7F; // max setupCount : fills the answer with 0 !

	smb_vwv[5]=0;

	smb_vwv[6]=0xFFF; // timeout

	smb_vwv[7]=0xFFF; // timeout

	smb_vwv[8]=0; //reserved

	smb_vwv[9]=paramLength;

//	smb_vwv[10]=; // see below

	smb_vwv[11]=dataLength;

//	smb_vwv[12]=; // see below

	smb_vwv[13]=setupLength;

	for (int i=0; i<setupLength; i++) smb_vwv[14+i]=setup[i];

	int nameSpace=(transactName)?strlen(transactName)+1:0;

	nameSpace+=nameSpace&0x1; // pad to next uint16

	int paramSpace=paramLength+(paramLength&0x1);

	smb_bcc=nameSpace+paramSpace+dataLength;

	smb_buf=new uint8[smb_bcc];

	if (transactName) strcpy((char*)smb_buf,(char*)transactName);

	if (paramLength) memcpy(smb_buf+nameSpace,param,paramLength);

	if (dataLength) memcpy(smb_buf+nameSpace+paramSpace,data,dataLength);

	// offset from header start to parameters

	smb_vwv[10]=35+((uint16)smb_wct)*2+nameSpace;

	// offset from header start to data

	smb_vwv[12]=smb_vwv[10]+paramSpace;

	modified=1;

}





SMBtranssPacket::SMBtranssPacket(uint16 tid, uint16 totalParameterCount,

		uint16 totalDataCount,

		uint16 paramDisplacement, // start of these param / total param

		uint16 dataDisplacement,

		uint8* param, uint16 paramLength,

		uint8* data, uint16 dataLength, uint8 dial)

{

	smb_com=SMBtranss;

	smb_tid=tid;

	smb_wct=8;

	smb_vwv=new uint16[smb_wct];

	smb_vwv[0]=totalParameterCount;

	smb_vwv[1]=totalDataCount;

	smb_vwv[2]=paramLength;

//	smb_vwv[3]=; // see below

	smb_vwv[4]=paramDisplacement;

	smb_vwv[5]=dataLength;

//	smb_vwv[6]=; // see below

	smb_vwv[7]=dataDisplacement;

	int paramSpace=paramLength+(paramLength&0x1);

	smb_bcc=1+paramSpace+dataLength;

	smb_buf=new uint8[smb_bcc];

	smb_buf[0]=0;	// pad to uint16

	if (paramLength) memcpy(smb_buf+1,param,paramLength);

	if (dataLength) memcpy(smb_buf+1+paramSpace,data,dataLength);

	// offset from header start to parameters

	smb_vwv[10]=35+8*2+1;

	// offset from header start to data

	smb_vwv[12]=smb_vwv[10]+paramSpace;

	modified=1;

}



uint16 SMBtranssPacket::getSetupCount()

{

	if (smb_wct<10) {errno=ERRerror; return 0;}

	if (smb_wct<10+smb_vwv[9]) {errno=ERRerror; return 0;}

	return smb_vwv[9];

}



uint16* SMBtranssPacket::getSetup()

{

	if (smb_wct<10) {errno=ERRerror; return 0;}

	if (smb_wct<10+smb_vwv[9]) {errno=ERRerror; return 0;}

	return (uint16*)((uint16*)smb_vwv+10);

}



uint16 SMBtranssPacket::getTotalParamCount()

{

	if (smb_wct<10) {errno=ERRerror; return 0;}

	return smb_vwv[0];

}



uint16 SMBtranssPacket::getTotalDataCount()

{

	if (smb_wct<10) {errno=ERRerror; return 0;}

	return smb_vwv[1];

}



uint16 SMBtranssPacket::getParamCount()

{

	if (smb_wct<10) {errno=ERRerror; return 0;}

	return smb_vwv[3];

}



uint16 SMBtranssPacket::getDataCount()

{

	if (smb_wct<10) {errno=ERRerror; return 0;}

	return smb_vwv[6];

}



uint16 SMBtranssPacket::getParamDisplacement()

{

	if (smb_wct<10) {errno=ERRerror; return 0;}

	return smb_vwv[5];

}



uint16 SMBtranssPacket::getDataDisplacement()

{

	if (smb_wct<10) {errno=ERRerror; return 0;}

	return smb_vwv[8];

}



uint8* SMBtranssPacket::getParam()

{

	if (smb_wct<10) {errno=ERRerror; return 0;}

	uint8* ret=new uint8[smb_vwv[3]];

	memcpy(ret,smb_buf+smb_vwv[4]-35-(uint16)(smb_wct)*2,smb_vwv[3]);

	return ret;

}



uint8* SMBtranssPacket::getData()

{

	if (smb_wct<10) {errno=ERRerror; return 0;}

	uint8* ret=new uint8[smb_vwv[6]];

	memcpy(ret,smb_buf+smb_vwv[7]-35-(uint16)(smb_wct)*2,smb_vwv[6]);

	return ret;

}

//#endif

#pragma code_seg()
#pragma data_seg()
#pragma bss_seg()
#pragma const_seg()

